import { ref } from 'vue';
import { clog, isNull } from '/@/utils';

type TApiFunc<TResult> = (params: any) => Promise<TResult>;

/**
 * @description 创建单例模式的Promise函数，pending状态时不会重复发起请求
 * @param target Promise函数
 * @returns 单例模式的Promise函数
 */
export function singletonPromise<TResult>(target: TApiFunc<TResult>) {
	// instance会闭包到singleton函数中，保证每次调用singleton函数时，instance都是同一个实例
	let instance: Promise<TResult> | null = null;

	const singleton = (params: any) => {
		if (!instance) {
			// 调用完成后要销毁, 避免内存泄漏, 并支持再次更新数据
			instance = target(params).finally(() => (instance = null));
		}

		return instance;
	};

	return singleton;
}

// 加载基础资料, 可以防止并发
export const useInitDataSingleton = <TResult>(fn: TApiFunc<TResult[]>) => {
	const singletonFun = singletonPromise(fn); // 单例方法, 防止并发调用
	let list = ref<TResult[]>([]);

	const initList = async () => {
		if (isNull(list.value)) {
			// 防止list为空时的并发调用
			list.value = await singletonFun({});
			// 使数组中的每个对象都变为只读 --> 不可行, 因为对象中的属性为对象时, 会导致对象不能读取(会报错)(比较奇怪)
			// list.value.forEach((obj) => Object.freeze(obj));
		}
		return list.value;
	};
	/** 强制刷新, 不使用缓存, 避免缓存数据不一致， 用于需要手动刷新前端换成的情况 */
	const initListForce = async () => {
		list.value = await fn({}); // 调用接口获取数据, 并赋值给list.value;
		return list.value;
	};
	return {
		list,
		initList,
		initListForce,
		singletonFun,
	};
};
